import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JButton;

public class ChatClient {
	private static int messagePort;
	private static String serverHost;
	private static int intervalMillisecond;
	private static Socket connection;
	private static boolean signIn = false;

	private static JTextField userNameTextField = new JTextField();
	private static JButton signButton = new JButton();
	private static JLabel statusLabel = new JLabel();
	private static JTextArea chatOutputTextArea = new JTextArea();
	private static JButton sendButton = new JButton();
	private static JTextField chatInputTextField = new JTextField();

	private static final String STATUS_LABEL_NOT_CONNECTED = "Not Connected";
	private static final String STATUS_LABEL_CONNECTED = "Connected";
	private static final String STATUS_LABEL_IN_USE = "Already in Use";
	private static final String SIGN_BUTTON_IN = "Sign In";
	private static final String SIGN_BUTTON_OUT = "Sign Out";

	public static void main(String args[]) throws IOException {
		loadConfig();

		initFrame();

		TimerTask task = new TimerTask() {
			public void run() {
				if (signIn) {
					Scanner in = null;
					try {
						if (connection.isClosed()) {
							return;
						}
						in = new Scanner(connection.getInputStream(), "UTF8");
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					try {
						String message = in.nextLine();
						chatOutputTextArea.append(message + "\n");
					} catch (NoSuchElementException e) {
						chatOutputTextArea.append("Chat Closed.");
					}
				}
			}
		};

		Timer timer = new Timer();
		timer.schedule(task, 0, intervalMillisecond);
	}

	private static void initFrame() {
		JFrame mainFrame = new JFrame();
		mainFrame.setSize(600, 410);
		mainFrame.setContentPane(getJContentPane());
		mainFrame.setTitle("Chat Client");
		mainFrame.setVisible(true);
		mainFrame.setLocation(600, 200);
		mainFrame.setResizable(false);
		mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	private static JPanel getJContentPane() {
		JLabel userNameLabel = new JLabel();
		userNameLabel.setText("User Name");

		ActionListener signActionListener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (signIn) {
					try {
						connection.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					signIn = false;
					userNameTextField.setEnabled(true);
					statusLabel.setText(STATUS_LABEL_NOT_CONNECTED);
					signButton.setText(SIGN_BUTTON_IN);
					chatInputTextField.setEnabled(false);
					sendButton.setEnabled(false);
				} else {
					String userName = userNameTextField.getText();
					try {
						SignInStatus signInStatus = signIn(userName);
						if (signInStatus == SignInStatus.OK) {
							signIn = true;
							userNameTextField.setEnabled(false);
							statusLabel.setText(STATUS_LABEL_CONNECTED);
							signButton.setText(SIGN_BUTTON_OUT);
							chatInputTextField.setEnabled(true);
							sendButton.setEnabled(true);

							chatOutputTextArea.setText("");
							chatInputTextField.setText("");
						} else if (signInStatus == SignInStatus.IN_USE) {
							statusLabel.setText(STATUS_LABEL_IN_USE);
						}
					} catch (UnknownHostException e1) {
						e1.printStackTrace();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
			}
		};

		userNameTextField.setPreferredSize(new Dimension(100, 23));
		userNameTextField.addKeyListener(new KeyListener() {
			public void keyPressed(KeyEvent arg0) {
				signButton.setEnabled(!userNameTextField.getText().isEmpty());
			}

			public void keyReleased(KeyEvent arg0) {
				signButton.setEnabled(!userNameTextField.getText().isEmpty());
			}

			public void keyTyped(KeyEvent arg0) {
				signButton.setEnabled(!userNameTextField.getText().isEmpty());
			}
		});
		userNameTextField.addActionListener(signActionListener);

		signButton.setText(SIGN_BUTTON_IN);
		signButton.addActionListener(signActionListener);
		signButton.setEnabled(false);

		statusLabel.setText(STATUS_LABEL_NOT_CONNECTED);

		chatOutputTextArea.setEditable(false);

		JScrollPane chatOutputScrollPane = new JScrollPane(chatOutputTextArea);
		chatOutputScrollPane.setPreferredSize(new Dimension(550, 250));
		chatOutputScrollPane
				.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

		ActionListener sendActionListener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String messageToSend = chatInputTextField.getText();
				if (!messageToSend.isEmpty()) {
					try {
						sendMessage(messageToSend);
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					chatInputTextField.setText("");
				}
			}
		};

		chatInputTextField.setPreferredSize(new Dimension(450, 23));
		chatInputTextField.addKeyListener(new KeyListener() {
			public void keyPressed(KeyEvent arg0) {
				sendButton.setEnabled(!chatInputTextField.getText().isEmpty());
			}

			public void keyReleased(KeyEvent arg0) {
				sendButton.setEnabled(!chatInputTextField.getText().isEmpty());
			}

			public void keyTyped(KeyEvent arg0) {
				sendButton.setEnabled(!chatInputTextField.getText().isEmpty());
			}
		});
		chatInputTextField.addActionListener(sendActionListener);
		chatInputTextField.setEnabled(false);

		sendButton.setText("Send");
		sendButton.addActionListener(sendActionListener);
		sendButton.setEnabled(false);

		JPanel jContentPane = new JPanel();
		jContentPane.add(userNameLabel);
		jContentPane.add(userNameTextField);
		jContentPane.add(signButton);
		jContentPane.add(statusLabel);
		jContentPane.add(chatOutputScrollPane);
		jContentPane.add(chatInputTextField);
		jContentPane.add(sendButton);

		return jContentPane;
	}

	private static SignInStatus signIn(String userName)
			throws UnknownHostException, IOException {
		connection = new Socket(serverHost, messagePort);

		PrintWriter out = new PrintWriter(new OutputStreamWriter(
				connection.getOutputStream(), "UTF8"), true);
		out.println(userName);
		out.flush();

		Scanner in = new Scanner(connection.getInputStream(), "UTF8");
		String signInStatus = in.nextLine();
		return Enum.valueOf(SignInStatus.class, signInStatus);
	}

	private static void sendMessage(String message) throws IOException {
		PrintWriter out = new PrintWriter(new OutputStreamWriter(
				connection.getOutputStream(), "UTF8"), true);
		out.println(message);
		out.flush();
	}

	private static void loadConfig() throws IOException {
		Properties prop = new Properties();
		FileReader in = null;
		in = new FileReader("./config.properties");
		prop.load(in);

		messagePort = Integer.parseInt(prop.getProperty("messagePort"));
		serverHost = prop.getProperty("serverHost");
		intervalMillisecond = Integer.parseInt(prop
				.getProperty("intervalMillisecond"));

		in.close();
	}
}
